/*
 * Copyright @ 苏州瑞云信息技术有限公司 All rights reserved.
 */
package cn.com.recloud.report.config;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import javax.servlet.ServletContext;

import io.minio.Result;
import io.minio.messages.Item;
import lombok.SneakyThrows;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
import com.bstek.ureport.exception.ReportException;
import com.bstek.ureport.provider.report.ReportFile;
import com.bstek.ureport.provider.report.ReportProvider;

import io.minio.MinioClient;
/**
 * @description:  基于ureport报表的minIO文件存储器
 * @author: wayne Wang
 * @date: 2020/7/28
 */
@Component
public class FileReportProvider implements ReportProvider {
    private String prefix="file:";
//    private String fileStoreDir;
    private boolean disabled;

    /**
     * 展示选中对象的信息，也就是从minIO上获取该对象的信息
     *      现状：
     *          没完成，没法从minIO上拿去报表进行展示
     *          原因：
     *              从minIo中提供的是一个InputStream(RealBuffered)流，但是ureport那里需要的是一个FileInputStream流，
     *              一个是内存级别的流，一个是基于本地磁盘读取的流，两种流的格式不同，会爆出错误，debug模式下走一会就可以看到错误信息。
     *              想法解决(没实现)：
     *                  1、使用中间缓冲流来转换试一试，没试过；
     *                  2、先将minio上的存到本地，然后在读取本地的报表进行展示；(感觉跟下载一样，没啥区别，和本质不太一样)
     * @param file
     * @return 输入流
     */
    @SneakyThrows
    @Override
    public InputStream loadReport(String file) {
        if(file.startsWith(prefix)){
            file = file.substring(prefix.length(),file.length());
        }
        InputStream testwang = null;
        try {
            MinioClient minioClient = new MinioClient("http://192.168.6.210:9000/", "admin", "p@ssw0rd");
            testwang = minioClient.getObject("testwang", file);
            FileInputStream f = (FileInputStream) testwang;
            System.out.println(testwang.getClass());
            return f;
        } catch (FileNotFoundException e) {
            throw new ReportException(e);
        }
    }

    /**
     * 根据传来的对象名称来删除储存中该对象
     * @param file
     */
    @SneakyThrows
    @Override
    public void deleteReport(String file) {
        // 截取字符串，用来获得对象名称(文件夹中文件的名称)
        if(file.startsWith(prefix)){
            file=file.substring(prefix.length(),file.length());
        }
        MinioClient minioClient = new MinioClient("http://192.168.6.210:9000/", "admin", "p@ssw0rd");
        minioClient.removeObject("testwang",file);
    }

    /**
     * 展示minIO文件存储服务器上储对应储存桶的多有对象信息
     * @return 返回对应存储桶上的所有对象信息
     */
    @lombok.SneakyThrows
    @Override
    public List<ReportFile> getReportFiles() {
        List<ReportFile> list=new ArrayList<ReportFile>();

        MinioClient minioClient = new MinioClient("http://192.168.6.210:9000/", "admin", "p@ssw0rd");
        // minIO传来的数据不支持类型转化，所以只能用这种迭代器的方式来将数据展示出来
        Iterable<Result<Item>> testwang = minioClient.listObjects("testwang");
        for (Result<Item> itemResult : testwang) {
            Item item = itemResult.get();
            Collection<Object> values = item.values();
            // minIO传来的数据不支持类型转化，所以只能用这种迭代器的方式来将数据展示出来
            Iterator iterator = values.iterator();
            // 文件/对象名称
            String name = "";
            // minIO上的时间
            String time = "";
            // ureport上的时间
            Date date = null;
            // 用来计算是第几个数据
            int count = 0;
            while(iterator.hasNext()) {
                Object object = iterator.next();
                System.out.println(object);
                // 传来的数据第二个是文件/对象名称
                if(count == 1)
                    name = (String) object;
                // 第二个是时间
                else if(count == 2) {
                    // 2020-07-28T10:00:54.560Z   minIO的日期格式
                    time = (String) object;
                    // 规定格式
                    time = time.replace("Z", " UTC");
                    // 进行时间处理
                    SimpleDateFormat sdf1 = new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss.SSS Z");
                    // Tue Jul 28 16:55:18 CST 2020  ureport按照这种格式
                    date=sdf1.parse(time);
                }
                count++;
            }
            list.add(new ReportFile(name,date));
        }
        Collections.sort(list, new Comparator<ReportFile>(){
            @Override
            public int compare(ReportFile f1, ReportFile f2) {
                return f2.getUpdateDate().compareTo(f1.getUpdateDate());
            }
        });
        return list;
    }

    @Override
    public String getName() {
        return "选我选我";
    }

    /**
     * 这是保存报表到存储服务器中的方法
     * @param file      文件名称，用来做在存储服务器中的存储对象的名字
     * @param content   文件内容，就是存储ureport中的内容
     */
    @Override
    public void saveReport(String file,String content) {
        if(file.startsWith(prefix)){
            file=file.substring(prefix.length(),file.length());
        }
        ByteArrayInputStream bais = null;
        try{
            MinioClient minioClient = new MinioClient("http://192.168.6.210:9000/", "admin", "p@ssw0rd");
            // 如存储桶不存在，创建之。
            boolean found = minioClient.bucketExists("testwang");
            if (!found) {
                // 创建名为'testwang'的存储桶。
                minioClient.makeBucket("testwang");
            }
            bais = new ByteArrayInputStream(content.getBytes("UTF-8"));
            // 实参的意义：在存储服务器中存储桶的名字， 存储桶中对象的名字， 要上传的流， 流的size， Content type
            minioClient.putObject("testwang", file, bais, bais.available(), "application/octet-stream");
            bais.close();
        }catch(Exception ex){
            throw new ReportException(ex);
        }finally{
            if(bais != null){
                try {
                    bais.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public boolean disabled() {
        return disabled;
    }

    public void setDisabled(boolean disabled) {
        this.disabled = disabled;
    }

    @Override
    public String getPrefix() {
        return prefix;
    }
}
